package local

import (
	"context"
	"errors"
	"gitee.com/gitee-go/core"
	"gitee.com/gitee-go/core/bean/hbtpBean"
	"gitee.com/gitee-go/core/bean/httpBean"
	"gitee.com/gitee-go/server/engine/agent"
	"gitee.com/gitee-go/utils"
	"gitee.com/gitee-go/utils/ioex"
	hbtp "github.com/mgr9525/HyperByte-Transfer-Protocol"
	"runtime/debug"
	"sync"
	"time"
)

/**
runner注册管理
*/
type ClientEngine struct {
	ctx context.Context

	runlk   sync.Mutex
	runners map[string]*agent.Client

	pluglk  sync.Mutex
	plugins map[string]*pluginItem
}

type pluginItem struct {
	cli *agent.Client
}

/**
启动,并初始化限制能注册的runner
*/
func StartClientEngine(ctx context.Context) *ClientEngine {
	c := &ClientEngine{
		ctx:     ctx,
		runners: make(map[string]*agent.Client),
		plugins: make(map[string]*pluginItem),
	}

	// 只能启动这些类型的runner
	c.plugins["build@maven"] = &pluginItem{}
	c.plugins["build@gradle"] = &pluginItem{}
	c.plugins["build@nodejs"] = &pluginItem{}
	c.plugins["build@python"] = &pluginItem{}
	c.plugins["build@ant"] = &pluginItem{}
	c.plugins["build@php"] = &pluginItem{}
	c.plugins["build@golang"] = &pluginItem{}
	c.plugins["shell@sh"] = &pluginItem{}
	c.plugins["shell@bash"] = &pluginItem{}
	//c.plugins["shell@powershell"]=pluginItem{}
	c.plugins["shell@git"] = &pluginItem{}
	c.plugins["shell@ssh"] = &pluginItem{}
	c.start()
	return c
}
func (c *ClientEngine) start() {
	go func() {
		for !ioex.CheckContext(c.ctx) {
			c.run()
			time.Sleep(time.Second)
		}
	}()
}

func (c *ClientEngine) run() {
	defer func() {
		if err := recover(); err != nil {
			core.LogPnc.Errorf("ClientEngine runRead:%+v", err)
			core.LogPnc.Errorf("%s", string(debug.Stack()))
		}
	}()

	//当runner超时后,删除队列
	c.runlk.Lock()
	defer c.runlk.Unlock()
	for k, v := range c.runners {
		if v.Stopd() {
			delete(c.runners, k)
		} else if time.Since(v.HeartTime()).Seconds() > 30 {
			v.Stop()
		}
	}
}

// 获取所有活动中的runner
func (c *ClientEngine) Runners() []*httpBean.RunnerItem {
	c.runlk.Lock()
	defer c.runlk.Unlock()

	ls := make([]*httpBean.RunnerItem, 0)
	for _, v := range c.runners {
		ls = append(ls, &httpBean.RunnerItem{
			Id:     v.Info().Id,
			Name:   v.Info().Name,
			Plugin: v.Info().Plugin,
		})
	}
	return ls
}

//注册
func (c *ClientEngine) Reg(hc *hbtp.Context, m *hbtpBean.RegReq) (string, error) {
	switch m.Type {
	case hbtpBean.RegTypeRunner:
		return c.regRunner(hc, m)
		//case hbtpBean.RegTypeAgent:
	}
	return "", errors.New("not found type")
}

// 注册
func (c *ClientEngine) regRunner(hc *hbtp.Context, m *hbtpBean.RegReq) (string, error) {
	defer func() {
		if err := recover(); err != nil {
			core.LogPnc.Errorf("ClientEngine RegRunner:%+v", err)
			core.LogPnc.Errorf("%s", string(debug.Stack()))
		}
	}()
	if len(m.Plugin) <= 0 {
		return "", errors.New("plugin is empty")
	}
	/*if len(m.Plugin)>1{
		return "",errors.New("plugin is more than")
	}*/

	c.pluglk.Lock()
	defer c.pluglk.Unlock()
	for _, v := range m.Plugin {
		pg, ok := c.plugins[v]
		if !ok {
			return "", errors.New("client plugin not available")
		} else if pg.cli != nil && !pg.cli.Stopd() {
			return "", errors.New("client plugin has bean reg")
		}
	}

	c.runlk.Lock()
	defer c.runlk.Unlock()
	if m.Id == "" {
		m.Id = utils.NewXid()
	} else {
		v, ok := c.runners[m.Id]
		if ok {
			v.Stop()
		}
	}
	cli := agent.StartClient(m, c.ctx, hc.Conn(true))
	c.runners[m.Id] = cli
	for _, v := range m.Plugin {
		pg := c.plugins[v]
		if pg.cli != nil {
			pg.cli.Stop()
		}
		pg.cli = cli
	}
	return m.Id, nil
}

// 获取runner的信息
func (c *ClientEngine) GetCliInfo(id string) (hbtpBean.RegReq, bool) {
	c.runlk.Lock()
	defer c.runlk.Unlock()

	v, ok := c.runners[id]
	if ok {
		return v.Info(), ok
	}
	return hbtpBean.RegReq{}, false
}
func (c *ClientEngine) ExistPlugRunner(plug string) bool {
	c.pluglk.Lock()
	defer c.pluglk.Unlock()
	pg, ok := c.plugins[plug]
	if !ok {
		return false
	} else if pg.cli == nil || pg.cli.Stopd() {
		return false
	}
	return true
}
